#include "candriver.h"
#include <QDebug>

CanDriver::CanDriver()
{

}

#ifdef EN_ZLGCAN
#pragma comment(lib, "ControlCAN.lib")

const sCanDev ZlgCanDev[] = {
    {"PCI5121", 0, 1},
    {"PCI9810", 1, 1},
    {"USBCAN1", 2, 1},
    {"USBCAN2", 3, 2},
    {"USBCAN2A", 4, 2},
    {"PCI9820", 5, 1},
    {"CAN232", 6, 1},
    {"PCI5110", 7, 1},
    {"CANLITE", 8, 1},
    {"ISA9620", 9, 1},
    {"ISA5420", 10, 1},
    {"PC104CAN", 11, 1},
    {"CANETUDP", 12, 1},
    {"CANETE", 13, 1},
    {"DNP9810", 14, 1},
    {"PCI9840", 15, 1},
    {"PC104CAN2", 16, 1},
    {"PCI9820I", 17, 1},
    {"CANETTCP", 18, 1},
    {"PEC9920", 19, 1},
    {"PCI5010U", 20, 1},
    {"USBCAN_E_U", 21, 1},
    {"USBCAN_2E_U", 22, 1},
    {"PCI5020U", 23, 1},
    {"EG2OT_CAN", 24, 1},
    };

sZLGTime mZLGTimeList[] = {
    {
        "5kbps",
        5,
        0xBF,
        0xFF,
    },
    {
        "10kbps",
        10,
        0x31,
        0x1C,
    },
    {
        "20kbps",
        20,
        0x18,
        0x1C,
    },
    {
        "40kbps",
        40,
        0x87,
        0xFF,
    },
    {
        "50kbps",
        50,
        0x09,
        0x1C,
    },
    {
        "80kbps",
        80,
        0x83,
        0Xff,
    },
    {
        "100kbps",
        100,
        0x04,
        0x1C,
    },
    {
        "125kbps",
        125,
        0x03,
        0x1C,
    },
    {
        "200kbps",
        200,
        0x81,
        0xFA,
    },
    {
        "250kbps",
        250,
        0x01,
        0x1C,
    },
    {
        "400kbps",
        400,
        0x80,
        0xFA,
    },
    {
        "500kbps",
        500,
        0x00,
        0x1C,
    },
    {
        "666kbps",
        666,
        0x80,
        0xB6,
    },
    {
        "800kbps",
        800,
        0x00,
        0x16,
    },
    {
        "1000kbps",
        1000,
        0x00,
        0x14,
    },
};

#define THREADSEND 1 // 是否采用多线程发送，可以加快ZLG的发送速度

ZlgCan::ZlgCan()
{
    m_devtype = 3;
    m_DevInd = 0;
    m_PortInd = 0;
}

bool ZlgCan::OpenDevice(QString sDevName, const sCanBaud mBaud)
{
    VCI_INIT_CONFIG mInitConfig;
    VCI_ERR_INFO mErrInfo;
    uint8_t uMode = 0;

    memset(&mInitConfig, 0, sizeof(mInitConfig));

    mInitConfig.AccCode = 0x00000000;
    mInitConfig.AccMask = 0xFFFFFFFF;
    mInitConfig.Filter = 0;

    if (mBaud.bUserDefBaud)
    {
        mInitConfig.Timing0 = mBaud.uBTR0;
        mInitConfig.Timing1 = mBaud.uBTR1;
    }
    else
    {
        int i = 0;
        for (i = 0; i < sizeof(mZLGTimeList) / sizeof(sZLGTime); i++)
        {
            if (mZLGTimeList[i].uBaud == mBaud.nBaud)
            {
                mInitConfig.Timing0 = mZLGTimeList[i].uBTR0;
                mInitConfig.Timing1 = mZLGTimeList[i].uBTR1;
                break;
            }
        }
        if (i == sizeof(mZLGTimeList) / sizeof(sZLGTime))
        {
            return false;
        }
    }

    mInitConfig.Mode = uMode;

    m_devtype = GetDevInd(sDevName);
    if (m_devtype < 0)
        return false;

    DWORD hRes = VCI_OpenDevice(m_devtype, m_DevInd, 0);

    if (hRes != STATUS_OK)
    {
        VCI_ReadErrInfo(m_devtype, m_DevInd, m_PortInd, &mErrInfo);
    }

    if (VCI_InitCAN(m_devtype, m_DevInd, m_PortInd, &mInitConfig) != STATUS_OK)
    {
        VCI_ReadErrInfo(m_devtype, m_DevInd, m_PortInd, &mErrInfo);
        return false;
    }

    if (VCI_StartCAN(m_devtype, m_DevInd, m_PortInd) != STATUS_OK)
    {
        VCI_ReadErrInfo(m_devtype, m_DevInd, m_PortInd, &mErrInfo);
        return false;
    }

    mCanSnd.m_devtype = m_devtype;
    mCanSnd.m_DevInd = m_DevInd;
    mCanSnd.m_PortInd = m_PortInd;
    mCanSnd.bRun = true;
    mCanSnd.start();
    return true;
}

bool ZlgCan::CloseDevice()
{
    mCanSnd.bRun = false;
    // Sleep(200); //

    VCI_ResetCAN(m_devtype, m_DevInd, m_PortInd);
    VCI_CloseDevice(m_devtype, m_DevInd);
    return true;
}

bool ZlgCan::SetBaud(uint32_t uBaud)
{
    (void)uBaud;
    return true;
}

bool ZlgCan::FindDev(QStringList &DevList)
{
    DevList.clear();
    for (int i = 0; i < sizeof(ZlgCanDev) / sizeof(sCanDev); i++)
    {
        DevList.append(ZlgCanDev[i].sName);
    }
    return false;
}

int ZlgCan::GetDevInd(QString sDevName)
{
    for (int i = 0; i < sizeof(ZlgCanDev) / sizeof(sCanDev); i++)
    {
        if (ZlgCanDev[i].sName == sDevName)
        {
            return ZlgCanDev[i].uDevNum;
        }
    }
    return -1;
}

int ZlgCan::Receive(sCANObj &msg, DWORD dwMilliseconds)
{
    VCI_CAN_OBJ frameinfo;
    VCI_ERR_INFO errinfo;

    if (VCI_Receive(m_devtype, m_DevInd, m_PortInd, &frameinfo, 1, dwMilliseconds))
    {
        msg.ID = frameinfo.ID;
        msg.uLen = frameinfo.DataLen;
        msg.TimeStamp = frameinfo.TimeStamp;
        msg.uCh = m_PortInd;
        msg.bDir = 0;
        memcpy(msg.Data, frameinfo.Data, 8);
        return 1;
    }
    else
    {
        VCI_ReadErrInfo(m_devtype, m_DevInd, m_PortInd, &errinfo);
        return 0;
    }
}

bool ZlgCan::Send(const sCANObj &msg)
{
#if (THREADSEND)
    if (mCanSnd.mSndFifo.count() < 100)
    {
        mCanSnd.mutex.lock();
        mCanSnd.mSndFifo.append(msg);
        mCanSnd.mutex.unlock();
        // SetEvent(mCanSnd.hTxEvent);
    }
    else
    {
        // ResetEvent(mCanSnd.hTxFinishEvent);
        // SetEvent(mCanSnd.hTxEvent);
        // DWORD dw = WaitForSingleObject(mCanSnd.hTxFinishEvent, 100);
        // if (dw == WAIT_OBJECT_0)
        // {
        //     mCanSnd.mutex.lock();
        //     mCanSnd.mSndFifo.append(msg);
        //     mCanSnd.mutex.unlock();
        //     return true;
        // }
        // else
        {
            qDebug() << "Send Error!!!!!!!!";
            return false;
        }
    }
    return true;
#else
    VCI_CAN_OBJ frameinfo;
    memcpy(frameinfo.Data, msg.Data, 8);
    frameinfo.ID = msg.ID;
    frameinfo.DataLen = msg.uLen;
    frameinfo.TimeStamp = msg.TimeStamp;
    frameinfo.RemoteFlag = msg.bRemote;
    frameinfo.ExternFlag = msg.bExtern;
    frameinfo.SendType = 0;
    return VCI_Transmit(m_devtype, m_DevInd, m_PortInd, &frameinfo, 1);
#endif
}

ULONG ZlgCan::GetSta()
{
    VCI_CAN_STATUS canstatus;
    if (VCI_ReadCANStatus(m_devtype, m_DevInd, m_PortInd, &canstatus) != STATUS_OK)
    {
        qDebug() << canstatus.regStatus << "," << canstatus.regTECounter << "," << canstatus.regMode;
        return 4;
    }
    else
    {
        //        qDebug() << canstatus.regStatus << "," << canstatus.regTECounter << "," << canstatus.regMode;
        //        return canstatus.regStatus;
        return 0;
    }
}

ZlgCanSnd::ZlgCanSnd()
{
    // hTxEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    // hTxFinishEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}

void ZlgCanSnd::run()
{
    VCI_CAN_OBJ frameinfo[100];
    sCANObj msg;

    while (bRun)
    {
        // DWORD dw = WaitForSingleObject(hTxEvent, 100);
        // if (dw == WAIT_OBJECT_0)
        // {
        // }
        int nSndCnt = mSndFifo.count();
        if (nSndCnt == 0)
        {
            // ResetEvent(hTxEvent);
            continue;
        }

        if (nSndCnt >= 50)
            nSndCnt = 50;

        for (int i = 0; i < nSndCnt; i++)
        {
            mutex.lock();
            msg = mSndFifo.head();
            mSndFifo.removeFirst();
            mutex.unlock();
            memcpy(frameinfo[i].Data, msg.Data, 8);
            frameinfo[i].ID = msg.ID;
            frameinfo[i].DataLen = msg.uLen;
            frameinfo[i].TimeStamp = msg.TimeStamp;
            frameinfo[i].RemoteFlag = msg.bRemote;
            frameinfo[i].ExternFlag = msg.bExtern;
            frameinfo[i].SendType = 0;
        }
        //        qDebug() << "TxCnd:" << nSndCnt;
        VCI_Transmit(m_devtype, m_DevInd, m_PortInd, &frameinfo[0], nSndCnt);
        // SetEvent(hTxFinishEvent);
    }
}
#endif

#ifdef EN_VECTOR
#pragma comment(lib, "vxlapi.lib")
#pragma comment(lib, "vxlapi64.lib")

VectorCan::VectorCan()
{
    XLstatus xlStatus;

    if (m_xlPortHandle != XL_INVALID_PORTHANDLE)
    {
        xlStatus = xlClosePort(m_xlPortHandle);
        printf("- ClosePort        : PH(0x%lx), %s\n", m_xlPortHandle, xlGetErrorString(xlStatus));
        xlStatus = xlCloseDriver();
    }
    // CloseHandle(m_hMsgEvent);
    m_xlPortHandle = XL_INVALID_PORTHANDLE;

    xlCloseDriver();
}

#define RX_QUEUE_SIZE 4096 // internal driver queue size in CAN events

bool VectorCan::isCantransceiver(unsigned short transceiverType)
{
    if ((transceiverType == XL_TRANSCEIVER_TYPE_PB_CAN_1041A_MAG)   // CancaseXL:XL_TRANSCEIVER_TYPE_PB_CAN_1041A_MAG
        || (transceiverType == XL_TRANSCEIVER_TYPE_PB_CAN_251)      // CancaseXL:XL_TRANSCEIVER_TYPE_PB_CAN_251
        || (transceiverType == XL_TRANSCEIVER_TYPE_PB_CAN_251_MAG)  // VN1640:XL_TRANSCEIVER_TYPE_PB_CAN_251_MAG
        || (transceiverType == XL_TRANSCEIVER_TYPE_PB_CAN_1051_CAP) // VN1640A:XL_TRANSCEIVER_TYPE_PB_CAN_1051_CAP
        || (transceiverType == XL_TRANSCEIVER_TYPE_PB_CAN_1057_CAP) // VN1640A:XL_TRANSCEIVER_TYPE_PB_CAN_1057_CAP
        || (transceiverType == XL_TRANSCEIVER_TYPE_CAN_1051_CAP_FIX)
        || (transceiverType == XL_TRANSCEIVER_TYPE_PB_CAN_251))
    { // VN1610:XL_TRANSCEIVER_TYPE_CAN_1051_CAP_FIX
        return true;
    }
    else
    {
        return false;
    }
}

bool VectorCan::OpenDevice(QString sDevName, const sCanBaud mBaud)
{
    XLstatus xlStatus;

    if (m_xlPortHandle != XL_INVALID_PORTHANDLE)
        return false;

    xlStatus = xlOpenDriver();

    QString sHWName = sDevName;
    QString sPortName;

    XLdriverConfig m_xlDrvConfig;
    unsigned int i = 0;

    if (XL_SUCCESS == xlStatus)
    {
        xlStatus = xlGetDriverConfig(&m_xlDrvConfig);
        for (i = 0; i < m_xlDrvConfig.channelCount; i++)
        {
            if ((m_xlDrvConfig.channel[i].hwType == XL_HWTYPE_NONE) || (m_xlDrvConfig.channel[i].hwType == XL_HWTYPE_VIRTUAL))
            { /*硬件为空或者虚拟的*/
                continue;
            }
            else
            {
                // if((m_xlDrvConfig.channel[i].transceiverType == XL_TRANSCEIVER_TYPE_PB_CAN_1041A_MAG) || (m_xlDrvConfig.channel[i].transceiverType == XL_TRANSCEIVER_TYPE_PB_CAN_251_MAG)){//CancaseXL:XL_TRANSCEIVER_TYPE_PB_CAN_1041A_MAG/VN1640:XL_TRANSCEIVER_TYPE_PB_CAN_251_MAG
                if ((sDevName == m_xlDrvConfig.channel[i].name) && isCantransceiver(m_xlDrvConfig.channel[i].transceiverType))
                { // VN1610:XL_TRANSCEIVER_TYPE_CAN_1051_CAP_FIX
                    m_xlChannelMask = (XLaccess)(0x00000001 << i);
                    break;
                }
                else
                {
                    continue;
                }
            }
        }
        if (i == m_xlDrvConfig.channelCount)
        { /* 找不到硬件 */
            return false;
        }
    }

    XLaccess m_xlPermissionMask = m_xlChannelMask;
    char g_AppName[XL_MAX_LENGTH + 1] = "xlCANcontrol";
    if (XL_SUCCESS == xlStatus)
    {
        xlStatus = xlOpenPort(&m_xlPortHandle, g_AppName, m_xlChannelMask, &m_xlPermissionMask, RX_QUEUE_SIZE, XL_INTERFACE_VERSION, XL_BUS_TYPE_CAN);
        printf("- OpenPort         : CM=0x%4x, PH=0x%02lX, PM=0x%4llx, %s\n",
               m_xlChannelMask, m_xlPortHandle, m_xlPermissionMask, xlGetErrorString(xlStatus));
    }

    if ((XL_SUCCESS == xlStatus) && (XL_INVALID_PORTHANDLE != m_xlPortHandle))
    {
        // if we have permission we set the bus parameters (baudrate)
        if (m_xlChannelMask == m_xlPermissionMask)
        {
            if (mBaud.bUserDefBaud)
            {
                xlStatus = xlCanSetChannelParamsC200(m_xlPortHandle, m_xlChannelMask, mBaud.uBTR0, mBaud.uBTR1);
                printf("- SetChannelBitrate: baudr.=%u, %s\n", mBaud.nBaud * 1000, xlGetErrorString(xlStatus));
            }
            else
            {
                xlStatus = xlCanSetChannelBitrate(m_xlPortHandle, m_xlChannelMask, mBaud.nBaud * 1000);
                printf("- SetChannelBitrate: baudr.=%u, %s\n", mBaud.nBaud * 1000, xlGetErrorString(xlStatus));
            }
        }
        else
        {
            printf("-                  : we have NO init access!\n");
            return FALSE;
        }
    }
    else
    {
        xlClosePort(m_xlPortHandle);
        m_xlPortHandle = XL_INVALID_PORTHANDLE;
        xlStatus = XL_ERROR;
    }

    xlStatus = xlActivateChannel(m_xlPortHandle, m_xlChannelMask, XL_BUS_TYPE_CAN, XL_ACTIVATE_RESET_CLOCK);
    memset(&hMsgEvent, 0, sizeof(hMsgEvent));
    xlStatus = xlSetNotification(m_xlPortHandle, &hMsgEvent, 1);

    //    sprintf_s(tmp, "ActivateChannel, stat: %d",  xlStatus);
    if (xlStatus)
        return false;
    return true;
}

bool VectorCan::CloseDevice()
{
    XLstatus xlStatus;
    QThread::msleep(200);

    if (m_xlPortHandle != XL_INVALID_PORTHANDLE)
    {
        xlStatus = xlDeactivateChannel(m_xlPortHandle, m_xlChannelMask);
        //	  printf("- DeativateChannel: CM(0x%I64x), %s\n", m_xlChannelMask, xlGetErrorString(xlStatus));	//此处会引起异常。
        if (xlStatus)
            return false;

        xlStatus = xlClosePort(m_xlPortHandle);
        //		printf("- ClosePort        : PH(0x%x), %s\n", m_xlPortHandle, xlGetErrorString(xlStatus));
        xlStatus = xlCloseDriver();
    }
    // CloseHandle(m_hMsgEvent);
    m_xlPortHandle = XL_INVALID_PORTHANDLE;
    return true;
}

bool VectorCan::SetBaud(uint32_t uBaud)
{
    (void)uBaud;
    return true;
}

bool VectorCan::FindDev(QStringList &DevList)
{
    DevList.clear();
    XLstatus xlStatus;

    if (m_xlPortHandle != XL_INVALID_PORTHANDLE)
        return false;

    xlStatus = xlOpenDriver();

    XLdriverConfig m_xlDrvConfig;
    unsigned int i = 0;

    if (XL_SUCCESS == xlStatus)
    {
        xlStatus = xlGetDriverConfig(&m_xlDrvConfig);
        for (i = 0; i < m_xlDrvConfig.channelCount; i++)
        {
            if ((m_xlDrvConfig.channel[i].hwType == XL_HWTYPE_NONE) || (m_xlDrvConfig.channel[i].hwType == XL_HWTYPE_VIRTUAL))
            { /*硬件为空或者虚拟的*/
                continue;
            }
            else
            {
                if (isCantransceiver(m_xlDrvConfig.channel[i].transceiverType))
                {
                    DevList.append(m_xlDrvConfig.channel[i].name);
                }
            }
        }
        if (i == m_xlDrvConfig.channelCount)
        { /* 找不到硬件 */
            return false;
        }
    }
    xlClosePort(m_xlPortHandle);
    return false;
}

bool VectorCan::Send(const sCANObj &msg)
{
    static XLevent xlEventTx;//, xlEventRx;
    XLstatus xlStatus;

    unsigned int messageCount = 1;

    memset(&xlEventTx, 0, sizeof(xlEventTx));
    xlEventTx.tag = XL_TRANSMIT_MSG;
    xlEventTx.tagData.msg.id = msg.bExtern ? (XL_CAN_EXT_MSG_ID | msg.ID) : msg.ID;
    xlEventTx.tagData.msg.dlc = msg.uLen;
    memcpy(xlEventTx.tagData.msg.data, msg.Data, 8);

    xlStatus = xlCanTransmit(m_xlPortHandle, m_xlChannelMask, &messageCount, &xlEventTx);
    if (xlStatus == XL_SUCCESS)
    {
        return true;
    }
    return false;
}

int VectorCan::Receive(sCANObj &msg, DWORD dwMilliseconds)
{
    XLstatus xlStatus;
    unsigned int msgsrx = 1;
    XLevent xlEvent;

    xlStatus = XL_SUCCESS;
    while (!xlStatus)
    {
        msgsrx = 1;
        xlStatus = xlReceive(m_xlPortHandle, &msgsrx, &xlEvent);
        if (xlStatus != XL_ERR_QUEUE_IS_EMPTY)
        {
            msg.ID = xlEvent.tagData.msg.id;
            msg.uLen = xlEvent.tagData.msg.dlc;
            msg.bDir = xlEvent.tagData.msg.flags;
            msg.uCh = 0;
            memcpy(msg.Data, xlEvent.tagData.msg.data, 8);
            msg.TimeStamp = xlEvent.timeStamp / 100000;
            return 1;
        }
        else
        {
            DWORD dw = WaitForSingleObject(hMsgEvent, dwMilliseconds);
            if (dw == WAIT_OBJECT_0)
            {
                xlStatus = XL_SUCCESS;
            }
            else if (dw == WAIT_FAILED)
            {
                return 0;
            }
        }
    }
    return 0;
}

ULONG VectorCan::GetSta()
{
    return 0;
}
#endif
